package webmanage

import (
	"context"
	"errors"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"gorm.io/gen"
	"gorm.io/gorm"
	"phm/internal/biz"
	"phm/internal/biz/webmanage"
	"phm/internal/conf"
	"phm/models/generator/model"
	"phm/models/generator/query"
	"strconv"
	"time"
)

type userRepo struct {
	Db  biz.DataRepo
	log *log.Helper
}

func NewUserRepo(data biz.DataRepo, logger log.Logger) webmanage.UserRepo {
	return &userRepo{Db: data, log: log.NewHelper(logger)}
}

func (u *userRepo) CreateUser(ctx context.Context, uModel *model.SysUser, db *gorm.DB) (string, error) {
	var s = db
	if db == nil {
		s = u.Db.GetDB()
	}
	opt := query.Use(s).SysUser
	err := opt.WithContext(ctx).Create(uModel)
	if err != nil {
		return "", err
	}
	token, err := u.Db.GetAuth().NewToken(ctx, uModel.ID, *uModel.RealName, *uModel.Mobile)
	if err != nil {
		return "", err
	}
	return token, nil
}

func (u *userRepo) DeleteUserByIds(ctx context.Context, ids []string, db *gorm.DB) error {
	var s = db
	if db == nil {
		s = u.Db.GetDB()
	}
	user := query.Use(s).SysUser
	info, err := user.WithContext(ctx).Where(user.ID.In(ids...)).Delete()
	u.log.Info(info)
	if err != nil {
		u.log.Errorf("删除用户错误：%v", ids)
		return err
	}
	return nil
}

func (u *userRepo) GetUserById(ctx context.Context, id string) (*model.SysUser, error) {
	s := u.Db.GetDB()
	opt := query.Use(s).SysUser
	user, err := opt.WithContext(ctx).Where(opt.ID.Eq(id)).First()
	if err != nil {
		return nil, err
	}
	return user, nil
}

func (u *userRepo) GetUserList(ctx context.Context, queryparam string, pageNum, pageSize int64) ([]*model.SysUser, int64, error) {
	s := u.Db.GetDB()
	opt := query.Use(s).SysUser
	if pageNum == 0 && pageSize == 0 {
		radars, err := opt.WithContext(ctx).Where(opt.IsSoftDelete.Eq(0)).Find()
		if err != nil {
			return nil, 0, err
		}
		return radars, 0, nil
	}
	var genCondition = []gen.Condition{}
	genCondition = append(genCondition, opt.IsSoftDelete.Eq(0))
	if queryparam != "" {
		genCondition = append(genCondition, opt.Username.Like("%"+queryparam+"%"))
	}
	list, err := opt.WithContext(ctx).Where(genCondition...).Limit(int(pageSize)).Offset(int((pageNum - 1) * pageSize)).Find()
	if err != nil {
		return nil, 0, err
	}
	// 计算总数
	count, _ := opt.WithContext(ctx).Where(opt.IsSoftDelete.Eq(0)).Count()
	return list, count, nil
}

func (u *userRepo) GetUserByUsername(ctx context.Context, username string) (*model.SysUser, error) {
	s := u.Db.GetDB()
	opt := query.Use(s).SysUser
	user, err := opt.WithContext(ctx).Where(opt.Username.Eq(username)).First()
	if err != nil {
		return nil, err
	}
	return user, nil
}

func (u *userRepo) GetUserByIds(ctx context.Context, ids []string) ([]*model.SysUser, error) {
	s := u.Db.GetDB()
	opt := query.Use(s).SysUser
	users, err := opt.WithContext(ctx).Where(opt.Username.In(ids...)).Find()
	if err != nil {
		return nil, err
	}
	return users, nil
}

func (u *userRepo) TryLogin(ctx context.Context, loginName string) (*model.SysUser, string, error) {
	var trylogintimes int32 = 1
	var usr *model.SysUser
	var err error
	// 默认五分钟
	cmd := u.Db.GetRedis().Get(ctx, loginPrefix(loginName))
	val := cmd.Val()
	ttl := u.Db.GetRedis().TTL(ctx, loginPrefix(loginName))
	duration, _ := time.ParseDuration("-1ns") // 过期。
	v, _ := strconv.ParseInt(val, 10, 32)
	if val == "" || ttl.Val() == duration { // 为空或者过期.
		u.Db.GetRedis().Set(ctx, loginPrefix(loginName), trylogintimes, conf.Config.Trylogin.ForbidMinuteInit.AsDuration())
	} else {
		if v == int64(conf.Config.Trylogin.Times) { // 等于设定的限制次数
			return nil, "", errors.New(fmt.Sprintf("重复尝试登录次数%v次已用完，请等%v分钟后重新尝试！", conf.Config.Trylogin.Times, conf.Config.Trylogin.ForbidMinuteInit.AsDuration().Minutes()))
		}
		u.Db.GetRedis().Set(ctx, loginPrefix(loginName), v+1, conf.Config.Trylogin.ForbidMinuteInit.AsDuration())
	}
	usr, err = u.GetUserByUsername(ctx, loginName)
	// conf.CONFIG.TryLogin.ForbidMinuteInit
	//u.dataRepo.GetRedis().Set(ctx, "login_"+loginName, trylogintimes
	return usr, fmt.Sprintf("这是第%v/%v次尝试", v+1, conf.Config.Trylogin.Times), err
}

func (u *userRepo) GetDB() *gorm.DB {
	return u.Db.GetDB()
}

func loginPrefix(name string) string {
	return "login_" + name
}
